{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "085cf314",
   "metadata": {},
   "source": [
    "# PyTorch: Loading Data from AIStore \n",
    "\n",
    "Listing and loading data from AIS buckets (buckets that are not 3rd party backend-based) and remote cloud buckets (3rd party backend-based cloud buckets) using [AISFileLister](https://pytorch.org/data/main/generated/torchdata.datapipes.iter.AISFileLister.html#aisfilelister) and [AISFileLoader](https://pytorch.org/data/main/generated/torchdata.datapipes.iter.AISFileLoader.html#torchdata.datapipes.iter.AISFileLoader).\n",
    "\n",
    "In the following example, we use the [Caltech-256 Object Category Dataset](https://authors.library.caltech.edu/7694/) containing 256 object categories and a total of 30607 images stored on an AIS bucket and the [Microsoft COCO Dataset](https://cocodataset.org/#home) which has 330K images with over 200K labels of more than 1.5 million object instances across 80 object categories stored on Google Cloud. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0e9e03de",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Imports\n",
    "import os\n",
    "from IPython.display import Image\n",
    "\n",
    "from torchdata.datapipes.iter import AISFileLister, AISFileLoader"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c42580f7",
   "metadata": {},
   "source": [
    "### Running the AIStore Cluster\n",
    "\n",
    "[AIStore](https://github.com/NVIDIA/aistore) (AIS for short) is a highly available lightweight object storage system that specifically focuses on petascale deep learning. As a reliable redundant storage, AIS supports n-way mirroring and erasure coding. But it is not purely – or not only – a storage system: it’ll shuffle user datasets and run custom extract-transform-load workloads.\n",
    "\n",
    "AIS is an elastic cluster that can grow and shrink at runtime and can be ad-hoc deployed, with or without Kubernetes, anywhere from a single Linux machine to a bare-metal cluster of any size. AIS fully supports Amazon S3, Google Cloud, and Microsoft Azure backends, providing a unified namespace across multiple connected backends and/or other AIS clusters, and [more](https://github.com/NVIDIA/aistore#features).\n",
    "\n",
    "[Getting started with AIS](https://github.com/NVIDIA/aistore/blob/master/docs/getting_started.md) will take only a few minutes (prerequisites boil down to having a Linux with a disk) and can be done either by running a prebuilt [all-in-one docker image](https://github.com/NVIDIA/aistore/tree/master/deploy) or directly from the open-source.\n",
    "\n",
    "To keep this example simple, we will be running a [minimal standalone docker deployment](https://github.com/NVIDIA/aistore/blob/master/deploy/prod/docker/single/README.md) of AIStore."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "51204353",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b8bba47bb72fc6eb4f9692966a3975ee6d7334a1989e8d6fb33084ca9cf2743f\r\n"
     ]
    }
   ],
   "source": [
    "# Running the AIStore cluster in a container on port 51080\n",
    "# Note: The mounted path should have enough space to load the dataset\n",
    "\n",
    "! docker run -d \\\n",
    "    -p 51080:51080 \\\n",
    "    -v <path_to_gcp_config>.json:/credentials/gcp.json \\\n",
    "    -e GOOGLE_APPLICATION_CREDENTIALS=\"/credentials/gcp.json\" \\\n",
    "    -e AWS_ACCESS_KEY_ID=\"AWSKEYIDEXAMPLE\" \\\n",
    "    -e AWS_SECRET_ACCESS_KEY=\"AWSSECRETEACCESSKEYEXAMPLE\" \\\n",
    "    -e AWS_DEFAULT_REGION=\"us-east-2\" \\\n",
    "    -e AIS_BACKEND_PROVIDERS=\"gcp aws\" \\\n",
    "    -v /disk0:/ais/disk0 \\\n",
    "    aistore/cluster-minimal:latest\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3b067695",
   "metadata": {},
   "source": [
    "To create and put objects (dataset) in the bucket, I am going to be using [AIS CLI](https://github.com/NVIDIA/aistore/blob/master/docs/cli.md). But we can also use the [Python SDK](https://github.com/NVIDIA/aistore/tree/master/sdk/python) for the same."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "730e1053",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"ais://caltech256\" created (see https://github.com/NVIDIA/aistore/blob/master/docs/bucket.md#default-bucket-properties)\n",
      "Files to upload:\n",
      "EXTENSION\t COUNT\t SIZE\n",
      "\t\t 1\t 3.06KiB\n",
      ".jpg\t\t 30607\t 1.08GiB\n",
      "TOTAL\t\t30608\t1.08GiB\n",
      "PUT 30608 objects to \"ais://caltech256\"\n"
     ]
    }
   ],
   "source": [
    "! ais config cli set cluster.url=http://localhost:51080\n",
    "\n",
    "# create bucket using AIS CLI\n",
    "! ais bucket create caltech256\n",
    "\n",
    "# put the downloaded dataset in the created AIS bucket\n",
    "! ais object put -r -y <path_to_dataset> ais://caltech256/"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b24bf6a8",
   "metadata": {},
   "source": [
    "### Preloaded dataset\n",
    "\n",
    "The following assumes that AIS cluster is running and one of its buckets contains Caltech-256 dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f26495b1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['ais://caltech256/002.american-flag/002_0001.jpg',\n",
       " 'ais://caltech256/002.american-flag/002_0002.jpg',\n",
       " 'ais://caltech256/002.american-flag/002_0003.jpg',\n",
       " 'ais://caltech256/002.american-flag/002_0004.jpg',\n",
       " 'ais://caltech256/002.american-flag/002_0005.jpg']"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# list of prefixes which contain data\n",
    "image_prefix = ['ais://caltech256/']\n",
    "\n",
    "# Listing all files starting with these prefixes on AIStore \n",
    "dp_urls = AISFileLister(url=\"http://localhost:51080\", source_datapipe=image_prefix)\n",
    "\n",
    "# list first 5 obj urls\n",
    "list(dp_urls)[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "eb311250",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "image url: ais://caltech256/002.american-flag/002_0001.jpg\n"
     ]
    },
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# loading data using AISFileLoader\n",
    "dp_files = AISFileLoader(url=\"http://localhost:51080\", source_datapipe=dp_urls)\n",
    "\n",
    "# check the first obj\n",
    "url, img = next(iter(dp_files))\n",
    "\n",
    "print(f\"image url: {url}\")\n",
    "Image(data=img.read())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "dd521f6a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def collate_sample(data):\n",
    "    path, image = data\n",
    "    dir = os.path.split(os.path.dirname(path))[1]\n",
    "    label_str, cls = dir.split(\".\")\n",
    "    return {\"path\": path, \"image\": image, \"label\": int(label_str), \"cls\": cls}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "39737c3f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# passing it further down the pipeline\n",
    "for _sample in dp_files.map(collate_sample):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9044a1cd",
   "metadata": {},
   "source": [
    "### Remote cloud buckets\n",
    "\n",
    "AIStore supports multiple [remote backends](https://aiatscale.org/docs/providers). With AIS, accessing cloud buckets doesn't require any additional setup assuming, of course, that you have the corresponding credentials (to access cloud buckets).\n",
    "\n",
    "For the following example, AIStore must be built and linked with the remote cloud provider backend which contains the dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "2cd03757",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['gcp://webdataset-testing/coco-train2014-seg-000000.tar',\n",
       " 'gcp://webdataset-testing/coco-train2014-seg-000001.tar',\n",
       " 'gcp://webdataset-testing/coco-train2014-seg-000002.tar',\n",
       " 'gcp://webdataset-testing/coco-train2014-seg-000003.tar',\n",
       " 'gcp://webdataset-testing/coco-train2014-seg-000004.tar']"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# list of prefixes which contain data\n",
    "gcp_prefix = ['gcp://webdataset-testing/']\n",
    "\n",
    "# Listing all files starting with these prefixes on AIStore \n",
    "gcp_urls = AISFileLister(url=\"http://localhost:51080\", source_datapipe=gcp_prefix)\n",
    "\n",
    "# list first 5 obj urls\n",
    "list(gcp_urls)[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "bccce8e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "dp_files = AISFileLoader(url=\"http://localhost:51080\", source_datapipe=gcp_urls)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ce89bc91",
   "metadata": {},
   "outputs": [],
   "source": [
    "for url, file in dp_files.load_from_tar():\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be29de09",
   "metadata": {},
   "source": [
    "### References\n",
    "- [AIStore](https://github.com/NVIDIA/aistore)\n",
    "- [AIStore Blog](https://aiatscale.org/blog)\n",
    "- [AIS CLI](https://github.com/NVIDIA/aistore/blob/master/docs/cli.md)\n",
    "- [AIStore Cloud Backend Providers](https://aiatscale.org/docs/providers)\n",
    "- [AIStore Documentation](https://aiatscale.org/docs)\n",
    "- [AIStore Python SDK](https://github.com/NVIDIA/aistore/tree/master/sdk/python)\n",
    "- [Caltech 256 Dataset](https://authors.library.caltech.edu/7694/)\n",
    "- [Getting started with AIStore](https://github.com/NVIDIA/aistore/blob/master/docs/getting_started.md)\n",
    "- [Microsoft COCO Dataset](https://cocodataset.org/#home)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
